// (C) Copyright 2012 Kystar. All rights reserved.

`timescale 1ns/100ps
`default_nettype none

module net_frame_disp_pkg 
(
    input  wire          I_sclk,
    input  wire          I_rst_n,
    // 
    input  wire          I_new_frame,
    input  wire          I_send_disp_set_pkg_start,
    // net arbitration
    output reg           O_req_net,
    input  wire          I_ack_net,
    // output
    output reg           O_net_out_en,
    output reg  [ 7: 0]  O_net_out_data,
    // ram interface
    // frame ram - 256 Byte
    output reg  [ 7: 0]  O_frame_pkg_ram_rdaddr,
    input  wire [ 7: 0]  I_frame_pkg_ram_rddata,
    // disp set ram - 1024 Byte
    output reg           O_sending_disp_set_pkg,
    output reg  [ 9: 0]  O_disp_set_pkg_ram_rdaddr,
    input  wire [ 7: 0]  I_disp_set_pkg_ram_rddata,
    // registers
    input  wire          I_reg_px_enable,
    input  wire [ 7: 0]  I_reg_nop_bytes,
    input  wire [ 8: 0]  I_reg_frame_pkg_byte_num,
    input  wire          I_reg_disable_disp_set_pkg,
    input  wire [ 10: 0] I_reg_disp_set_pkg_byte_num
);

/******************************************************************************
                                <localparams>
******************************************************************************/
localparam
    NET_HEAD_BYTES = 8;

localparam // state
    IDLE = 0,
    NET_REQ = 1,
    SEND_NET_HEAD = 1<<1,
    SEND_FRAME_DATA = 1<<2,
    NOP = 1<<3,
    SEND_DISP_DATA = 1<<4;

/******************************************************************************
                              <internal signals>
******************************************************************************/
reg  [ 4: 0] state;
reg  [ 4: 0] next_state;
reg  is_frame_pkg;
reg  [ 7: 0] frame_data_cnt;
reg  [ 7: 0] nop_cnt;
reg  [ 9: 0] disp_data_cnt;
reg  is_second_frame_pkg;
reg  [ 3: 0] head_cnt;

/******************************************************************************
                                <module body>
******************************************************************************/

// state machine : state
always @(posedge I_sclk or negedge I_rst_n)
    if (!I_rst_n)
        state <= IDLE;
    else if ((I_new_frame || I_send_disp_set_pkg_start) && I_reg_px_enable)
        state <= NET_REQ;
    else
        state <= next_state;

always @(*)
    case (state)
        IDLE:
            next_state = IDLE;
        NET_REQ:
            if (I_ack_net)
                next_state = SEND_NET_HEAD;
            else
                next_state = NET_REQ;
        SEND_NET_HEAD:
            if (head_cnt == NET_HEAD_BYTES - 1)
                begin
                if (is_frame_pkg)
                    next_state = SEND_FRAME_DATA;
                else
                    next_state = SEND_DISP_DATA;
                end
            else
                next_state = SEND_NET_HEAD;
        SEND_FRAME_DATA:
            if (frame_data_cnt == I_reg_frame_pkg_byte_num - 1'b1)
                next_state = NOP;
            else
                next_state = SEND_FRAME_DATA;
        NOP:
            if (nop_cnt == I_reg_nop_bytes - 4)
                begin
                if (!is_frame_pkg)
                    begin
                    if (I_reg_disable_disp_set_pkg)
                        next_state = IDLE;
                    else
                        next_state = SEND_NET_HEAD;
                    end
                else
                    next_state = SEND_NET_HEAD;
                end
            else
                next_state = NOP;
        SEND_DISP_DATA:
            if (disp_data_cnt == I_reg_disp_set_pkg_byte_num - 1'b1)
                next_state = IDLE;
            else
                next_state = SEND_DISP_DATA;
        default:
            next_state = IDLE;
    endcase

always @(posedge I_sclk or negedge I_rst_n)
    if (!I_rst_n)
        O_sending_disp_set_pkg <= 1'b0;
    else if (state == IDLE)
        O_sending_disp_set_pkg <= 1'b0;
    else if (state == NOP && nop_cnt == 'd0 && is_second_frame_pkg)
        O_sending_disp_set_pkg <= 1'b1;

always @(posedge I_sclk or negedge I_rst_n)
    if (!I_rst_n)
        is_frame_pkg <= 1'b0;
    else if (I_send_disp_set_pkg_start)
        is_frame_pkg <= 1'b0;
    else if (I_new_frame)
        is_frame_pkg <= 1'b1;
    else if (state == SEND_FRAME_DATA)
        begin
        if (is_second_frame_pkg)
            is_frame_pkg <= 1'b0;
        end

always @(posedge I_sclk or negedge I_rst_n)
    if (!I_rst_n)
        is_second_frame_pkg <= 1'b0;
    else if (I_new_frame)
        is_second_frame_pkg <= 1'b0;
    else if (state == NOP)
        is_second_frame_pkg <= 1'b1;

always @(posedge I_sclk or negedge I_rst_n)
    if (!I_rst_n)
        O_req_net <= 1'b0;
    else if (state == IDLE)
        O_req_net <= 1'b0;
    else
        O_req_net <= 1'b1;

always @(posedge I_sclk or negedge I_rst_n)
    if (!I_rst_n)
        head_cnt <= 'd0;
    else if (state == SEND_NET_HEAD)
        head_cnt <= head_cnt + 1;
    else
        head_cnt <= 'd0;

always @(posedge I_sclk or negedge I_rst_n)
    if (!I_rst_n)
        O_net_out_en <= 1'b0;
    else if (state == SEND_NET_HEAD || state == SEND_FRAME_DATA || state == SEND_DISP_DATA)
        O_net_out_en <= 1'b1;
    else
        O_net_out_en <= 1'b0;

always @(posedge I_sclk or negedge I_rst_n)
    if (!I_rst_n)
        O_net_out_data <= 8'h0;
    else if (state == SEND_NET_HEAD)
        begin
        if (head_cnt == NET_HEAD_BYTES - 1'b1)
            O_net_out_data <= 8'hD5;
        else
            O_net_out_data <= 8'h55;
        end
    else if (state == SEND_FRAME_DATA)
        O_net_out_data <= I_frame_pkg_ram_rddata;
    else if (state == SEND_DISP_DATA)
        O_net_out_data <= I_disp_set_pkg_ram_rddata;
    else
        O_net_out_data <= 'd0;

always @(posedge I_sclk or negedge I_rst_n)
    if (!I_rst_n)
        O_frame_pkg_ram_rdaddr <= 'd0;
    else if (I_new_frame)
        O_frame_pkg_ram_rdaddr <= 'd0;
    else if (state == SEND_NET_HEAD && head_cnt == NET_HEAD_BYTES - 'd2)
        O_frame_pkg_ram_rdaddr <= 'd1;
    else if (state == SEND_NET_HEAD && head_cnt == NET_HEAD_BYTES - 1'b1)
        O_frame_pkg_ram_rdaddr <= 'd2;
    else if (state == SEND_FRAME_DATA)
        O_frame_pkg_ram_rdaddr <= O_frame_pkg_ram_rdaddr + 1'b1;
    else
        O_frame_pkg_ram_rdaddr <= 'd0;

always @(posedge I_sclk or negedge I_rst_n)
    if (!I_rst_n)
        frame_data_cnt <= 'd0;
    else if (state == SEND_FRAME_DATA)
        frame_data_cnt <= frame_data_cnt + 1;
    else
        frame_data_cnt <= 'd0;

always @(posedge I_sclk or negedge I_rst_n)
    if (!I_rst_n)
        nop_cnt <= 'd0;
    else if (state == NOP)
        nop_cnt <= nop_cnt + 1;
    else
        nop_cnt <= 'd0;

always @(posedge I_sclk or negedge I_rst_n)
    if (!I_rst_n)
        disp_data_cnt <= 'd0;
    else if (state == SEND_DISP_DATA)
        disp_data_cnt <= disp_data_cnt + 1;
    else
        disp_data_cnt <= 'd0;

always @(posedge I_sclk or negedge I_rst_n)
    if (!I_rst_n)
        O_disp_set_pkg_ram_rdaddr <= 'd0;
    else if (I_new_frame)
        O_disp_set_pkg_ram_rdaddr <= 'd0;
    else if (state == SEND_NET_HEAD && head_cnt == NET_HEAD_BYTES - 'd2)
        O_disp_set_pkg_ram_rdaddr <= 'd1;
    else if (state == SEND_NET_HEAD && head_cnt == NET_HEAD_BYTES - 1'b1)
        O_disp_set_pkg_ram_rdaddr <= 'd2;
    else if (state == SEND_DISP_DATA)
        O_disp_set_pkg_ram_rdaddr <= O_disp_set_pkg_ram_rdaddr + 1'b1;
    else
        O_disp_set_pkg_ram_rdaddr <= 'd0;

endmodule
`default_nettype wire

